package cn.alpha.workflow.controller;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipInputStream;

import javax.servlet.http.HttpServletResponse;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamReader;

import org.activiti.bpmn.converter.BpmnXMLConverter;
import org.activiti.bpmn.model.BpmnModel;
import org.activiti.editor.constants.ModelDataJsonConstants;
import org.activiti.editor.language.json.converter.BpmnJsonConverter;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.Model;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.repository.ProcessDefinitionQuery;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;

import cn.alpha.workflow.vo.DTRequestParam;
import cn.alpha.workflow.vo.DTResponseData;
import cn.ffcs.shequ.bo.Result;

/**
 	act_re_procdef：流程定义数据表，此表和ACT_RE_DEPLOYMENT是多对一的关系，
	即，一个部署的bar包里可能包含多个流程定义文件，
	每个流程定义文件都会有一条记录在ACT_REPROCDEF表内，
	每个流程定义的数据，都会对于ACT_GE_BYTEARRAY表内的一个资源文件和PNG图片文件。
	和ACT_GE_BYTEARRAY的关联是通过程序用ACT_GE_BYTEARRAY.NAME与
	ACT_RE_PROCDEF.NAME_完成的，在数据库表结构中没有体现
	CREATE TABLE act_re_procdef (
	  ID_ varchar(64) comment '',
	  REV_ int(11) comment '乐观锁',
	  CATEGORY_ varchar(255) comment '分类, 流程定义的targetNamespace就是类别,',
	  NAME_ varchar(255) comment '名称，流程文件process元素的name属性',
	  KEY_ varchar(255) comment '定义的KEY, 流程文件process元素id属性',
	  VERSION_ int(11) comment '版本',
	  DEPLOYMENT_ID_ varchar(64) comment '部署表ID',
	  RESOURCE_NAME_ varchar(4000) comment '流程bpmn文件名称',
	  DGRM_RESOURCE_NAME_ varchar(4000) comment '流程图片名称',
	  DESCRIPTION_ varchar(4000) comment '描述',
	  HAS_START_FORM_KEY_ tinyint(4) comment '是否存在开始节点formKey,0否,1是',
	  SUSPENSION_STATE_ int(11) comment '是否挂起,1 激活 2挂起',
	  TENANT_ID_ varchar(255) comment '',
	  HAS_GRAPHICAL_NOTATION_ tinyint(4) ,
	  PRIMARY KEY (ID_),
	  UNIQUE KEY ACT_UNIQ_PROCDEF (KEY_,VERSION_,TENANT_ID_)
	  
	  resource_name, dgrm_resource_name,
	  ID, category, name, key, version,  description suspension_state,
   部署时间

 */ 
@Controller("procdefController")
public class ProcdefController extends AbstractController 
{
	@RequestMapping(value = "/procdef/deploy")
    @ResponseBody
    public Object deploy(MultipartFile importFile) 
    {
		String fileName = importFile.getOriginalFilename();
    	Result res=new Result();
        try {
        	InputStream fileInputStream = importFile.getInputStream();
            Deployment deployment = null;

            String extension = FilenameUtils.getExtension(fileName);
            if (extension.equals("zip") || extension.equals("bar")) {
                ZipInputStream zip = new ZipInputStream(fileInputStream);
                deployment = repositoryService.createDeployment().addZipInputStream(zip).deploy();
            } else {
                deployment = repositoryService.createDeployment().addInputStream(fileName, fileInputStream).deploy();
            }

            repositoryService.createProcessDefinitionQuery().deploymentId(deployment.getId()).list();
            res.setResult(fileName);
        } catch (Exception e) {
            logger.error("部署流程失败：", e);
            res.setNote(e.getMessage());
        }
        return res;
    }
	

	@RequestMapping(value = "/procdef/export")
    public void export(String procdefId,String type,HttpServletResponse response) throws IOException 
	{
		ProcessDefinition procdef = repositoryService.createProcessDefinitionQuery()
				.processDefinitionId(procdefId).singleResult();
		String resourceName = "";
		if (type.equals("image")) 
			resourceName = procdef.getDiagramResourceName();
		else if (type.equals("xml")) 
			resourceName = procdef.getResourceName();
		
		InputStream resourceAsStream = repositoryService.getResourceAsStream(procdef.getDeploymentId(),resourceName);
		response.reset();
		response.setCharacterEncoding("utf-8");  
        response.setContentType("multipart/form-data");  
        response.setContentType("application/octet-stream");
        response.setContentLength(resourceAsStream.available());
        response.setHeader("Content-Disposition", "attachment;fileName="+ resourceName);
        response.flushBuffer();
        
        IOUtils.copy(resourceAsStream, response.getOutputStream());
    }
	
	//查看
	@RequestMapping(value = "/procdef/view")
    public void view(String procdefId,HttpServletResponse response) throws IOException 
	{
		ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
                .processDefinitionId(procdefId).singleResult();
		InputStream imageStream = repositoryService.getResourceAsStream(processDefinition.getDeploymentId(),
                 processDefinition.getDiagramResourceName());
        if(imageStream!=null)
        	IOUtils.copy(imageStream, response.getOutputStream());
	}
	
	@RequestMapping(value = "/procdef/convert2M")
    @ResponseBody
    public Object convert2M(String procdefId) 
    {
    	Result res=new Result();
        try {
        	ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
                    .processDefinitionId(procdefId).singleResult();
            InputStream bpmnStream = repositoryService.getResourceAsStream(processDefinition.getDeploymentId(),
                    processDefinition.getResourceName());
            XMLInputFactory xif = XMLInputFactory.newInstance();
            InputStreamReader in = new InputStreamReader(bpmnStream, "UTF-8");
            XMLStreamReader xtr = xif.createXMLStreamReader(in);
            BpmnModel bpmnModel = new BpmnXMLConverter().convertToBpmnModel(xtr);

            BpmnJsonConverter converter = new BpmnJsonConverter();
            com.fasterxml.jackson.databind.node.ObjectNode modelNode = converter.convertToJson(bpmnModel);
            Model modelData = repositoryService.newModel();
            modelData.setKey(processDefinition.getKey());
            modelData.setName(processDefinition.getResourceName());
            modelData.setCategory(processDefinition.getDeploymentId());

            ObjectNode modelObjectNode = new ObjectMapper().createObjectNode();
            modelObjectNode.put(ModelDataJsonConstants.MODEL_NAME, processDefinition.getName());
            modelObjectNode.put(ModelDataJsonConstants.MODEL_REVISION, 1);
            modelObjectNode.put(ModelDataJsonConstants.MODEL_DESCRIPTION, processDefinition.getDescription());
            modelData.setMetaInfo(modelObjectNode.toString());

            repositoryService.saveModel(modelData);

            repositoryService.addModelEditorSource(modelData.getId(), modelNode.toString().getBytes("utf-8"));
            res.setResult(modelData.getId());
        } catch (Exception e) {
            logger.error("转换模型失败：", e);
            res.setNote(e.getMessage());
        }
        return res;
    }
	
	@RequestMapping(value = "/procdef/updateState")
	@ResponseBody
    public Object updateState(String procdefId,boolean state) 
	{
		Result res=new Result();
		if(state)
			repositoryService.activateProcessDefinitionById(procdefId, true, null);
		else
			repositoryService.suspendProcessDefinitionById(procdefId, true, null);
        res.setResult(procdefId);
        return res;
    }
	
	@RequestMapping(value = "/procdef/delete")
	@ResponseBody
    public Object delete(String deploymentId) 
	{
		Result res=new Result();
		repositoryService.deleteDeployment(deploymentId, true);
        res.setResult(deploymentId);
        return res;
    }
	

    @RequestMapping(value = "/procdef/list")
    @ResponseBody
    public Object list(@RequestBody DTRequestParam dtRequestParam) 
    {
    	ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery();
    	String searchStr=dtRequestParam.getSearch().getValue();
    	if(!StringUtils.isEmpty(searchStr))
    		processDefinitionQuery.processDefinitionNameLike("%"+searchStr+"%");
        List<ProcessDefinition> processDefinitionList = processDefinitionQuery
        			.listPage(dtRequestParam.getStart(),dtRequestParam.getLength());
        List<Map<String,Object>> resList=new ArrayList<Map<String,Object>>();
        Map<String,Object> item;
        Deployment deployment;
        for (ProcessDefinition processDefinition : processDefinitionList) 
        {
        	item=new HashMap<String, Object>();
        	item.put("id", processDefinition.getId());
        	item.put("name", processDefinition.getName());
        	item.put("key", processDefinition.getKey());
        	item.put("category", processDefinition.getCategory());
        	item.put("version", processDefinition.getVersion());
        	item.put("description", processDefinition.getDescription());
        	item.put("suspensionState", processDefinition.isSuspended()?"挂起":"激活");
        	item.put("suspensionStateCode", processDefinition.isSuspended());
            String deploymentId = processDefinition.getDeploymentId();
            deployment = repositoryService.createDeploymentQuery().deploymentId(deploymentId).singleResult();
            item.put("deployDT", deployment.getDeploymentTime());
            item.put("deploymentId", deployment.getId());
            resList.add(item);
        }
    	Long total=processDefinitionQuery.count();
    	return new DTResponseData(resList, total, dtRequestParam.getDraw());
    }
	
}
